package com.hotai.comment.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.hotai.comment.dtos.ResponseResult;
import com.hotai.comment.enums.AppHttpCodeEnum;
import com.hotai.comment.enums.AppJwtUtil;
import com.hotai.comment.pojo.UserStudent;
import com.hotai.mapper.UserStudentMapper;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jettison.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private UserStudentMapper  userStudentMapper;


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //关于浏览器的请求预检.在跨域的情况下，非简单请求会先发起一次空body的OPTIONS请求，称为"预检"请求，用于向服务器请求权限信息，等预检请求被成功响应后，才发起真正的http请求。
        if ("OPTIONS".equals(request.getMethod())) {
            return true; //true是直接放行，前端抓包会有options请求
            //false拒接访问，抓包就不会有options请求了
        }
//        String token = request.getParameter("token");   放入params才能用这个，放hearder用getHearder
        String token = request.getHeader("Authorization");
        if (token == null) {
            ResponseResult resultVO = ResponseResult.errorResult(403, "请先登录！");
            doResponse(response,resultVO);
        } else {
            try {
                Claims claimsBody = AppJwtUtil.getClaimsFromToken(token);//解析token
                UserStudent userStudent = userStudentMapper.selectById(claimsBody.getId());

                if (userStudent!=null){
                    if (claimsBody!=null){
                        String o = redisTemplate.opsForValue().get(claimsBody.getId());//获取redis token  比较
                        if (StringUtils.isNotBlank(o)){
                            if (!o.equals(token)){
                                ResponseResult resultVO = new ResponseResult(409, "此账号已在别处登录！", null);
                                doResponse(response,resultVO);
                                return  false;
                            }
                        }
               }
            }

                //是否过期  并刷新过期时间
                int i = AppJwtUtil.verifyToken(claimsBody);
                if (i==1){
                    ResponseResult resultVO = new ResponseResult(401, "登录过期，请重新登录！", null);
                    doResponse(response, resultVO);
                    return  false;
                }

                JwtParser parser = Jwts.parser();
                parser.setSigningKey(AppJwtUtil.generalKey()); //解析token的SigningKey必须和生成token时设置密码一致
                //如果token检验通过（密码正确，有效期内）则正常执行，否则抛出异常
                    Jws<Claims> claimsJws = parser.parseClaimsJws(token);
                    return true;//true就是验证通过，放行

            } catch (ExpiredJwtException e) {
                ResponseResult resultVO = new ResponseResult(401, "登录过期，请重新登录！", null);
                doResponse(response, resultVO);
            } catch (UnsupportedJwtException e) {
                ResponseResult resultVO = new ResponseResult(106, "Token不合法，请自重！", null);
                doResponse(response, resultVO);
            } catch (Exception e) {
                ResponseResult resultVO = new ResponseResult(403, "请先登录！", null);
                doResponse(response, resultVO);
            }
        }
        return false;
    }




    //没带token或者检验失败响应给前端
    private void doResponse(HttpServletResponse response, ResponseResult resultVO) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        String s = new ObjectMapper().writeValueAsString(resultVO);
        out.print(s);
        out.flush();
        out.close();
    }



}